
public abstract class List {

	private Node head = null;
	private Node tail = null;
	
	protected static class Node {
		Object element;
		Node next = null;
		Node previous = null;
		
		Node(Object element) {
			this.element = element;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result
					+ ((element == null) ? 0 : element.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj) {
				return true;
			}
			if (obj == null) {
				return false;
			}
			if (getClass() != obj.getClass()) {
				return false;
			}
			Node other = (Node) obj;
			if (element == null) {
				if (other.element != null) {
					return false;
				}
			} else if (!element.equals(other.element)) {
				return false;
			}
			return true;
		}
	}
	
	// adds new element of type object to list, returns true if successful false if not
	public boolean add(Object element) {
		if(head == null) {
			head = tail = new Node(element);
		} else {
			Node currTail = tail;
			Node newTail = new Node(element);
			currTail.next = newTail;
			newTail.previous = currTail;
			tail = newTail;
		}
		return true;
	}
	
	// removes object with given identifier from list, in this case the id ist the object to remove
	public boolean remove(Object element) {
		if(head == null) {
			// list is empty
			return false;
		}
		Node elemNode = new Node(element);
		Node objToTest = head;
		do {
			if(objToTest.equals(elemNode)) {
				if(objToTest == head) {
					head.next.previous = null;
					head = head.next;
				} else if(objToTest == tail) {
					tail.previous.next = null;
					tail = tail.previous;
				} else {
					objToTest.next.previous = objToTest.previous;
					objToTest.previous.next = objToTest.next;
				}
				return true;
			}
		} while((objToTest = objToTest.next) != null);
		return false;
	}
	
	// returns the object with the given identifier, null if not found or id invalid
	public abstract Object getElement(Object objId);
	
	protected Iterator iterator() {
		return new Iterator();
	}
	
	protected class Iterator implements Iter {
		private Node current = null;
		
		protected Iterator() {
			current = head;
		}
		
		public boolean hasNext() {
			return current != null;
		}
		
		public Object next() {
			if(current == null) {
				return null;
			}
			Object elem = current.element;
			current = current.next;
			return elem;
		}
	}
	
	@Override
	public String toString(){
		String s = "";
		Iterator i = iterator();
		while(i.hasNext()){
			s += i.next().toString()+"\n";
		}
		
		return s;
	}
}
